package org.example.cicdi.service.impl.third;

import com.alibaba.fastjson.JSONObject;
import com.google.gson.Gson;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.example.cicdi.enums.EnumWhiteColumnAnnotation;
import org.example.cicdi.enums.EnumWhiteTableAnnotation;
import org.example.cicdi.service.impl.ext.FieldAnnotationServiceExt;
import org.example.cicdi.service.impl.org.TableAnnotationService;
import org.example.cicdi.service.impl.second.FieldfacaService;
import org.example.cicdi.service.impl.second.TbfacaService;
import org.example.cicdi.service.impl.third.handlewebvo.HandleWebVo;
import org.example.cicdi.service.impl.third.handlewebvo.HandleWebVo2;
import org.example.cicdi.utils.HttpUtils;
import org.example.codegenerate.modelext.WebVo.Enum.EnumModelType;
import org.example.codegenerate.modelext.WebVo.Enum.EnumTableType;
import org.example.codegenerate.modelext.WebVo.annotation.table.TVo;
import org.example.codegenerate.modelext.WebVo.annotation.table.WVo;
import org.example.codegenerate.modelext.WebVo.domian.column.ColumnVoDomain;
import org.example.codegenerate.modelext.WebVo.domian.table.TableVoDomain;
import org.example.codegenerate.modelext.WebVo.domian.table.WebModelVo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;
import org.springframework.core.io.FileSystemResource;
import org.springframework.core.io.Resource;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import org.springframework.core.io.support.ResourcePatternResolver;
import org.springframework.core.type.classreading.CachingMetadataReaderFactory;
import org.springframework.core.type.classreading.MetadataReader;
import org.springframework.core.type.classreading.MetadataReaderFactory;
import org.springframework.stereotype.Service;
import org.springframework.util.ClassUtils;

import javax.persistence.Table;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.Iterator;
import java.util.List;

@Slf4j
@Data
//@Service
public class StarterCodeServiceExtSecond {
	/*
	 * ManyToOne：org.jeecg.modules.cicdi.jpa.project.child； OneToMany:org.jeecg.modules.cicdi.jpa.project.parent
	 * 2个标签不要嵌套使用，否则死循环
	 */
	@Value("${jpacode.basepackage}")
	private  String BASE_PACKAGE ;
	
    private static final String RESOURCE_PATTERN = "/**/*.class";
    
    //@Autowired
    private List<TableAnnotationService>tableServices;
    
    //@Autowired
    private List<FieldAnnotationServiceExt>fieldServices;
	//@Autowired
	private TbfacaService tbfacaService;
	//@Autowired
	private FieldfacaService fieldfacaService;

	@Value("${jpacode.jpaserverurl}")
	private String jpaserverurl;
	@Value("${jpacode.includedeployway}")
	private String includedeployway;


	public void process() throws Exception {

		//1.读取所有需要生成代码的jpa类
		List<Class<?>> list = queryAllJpa();
		if (CollectionUtils.isEmpty(list)) {
			return;
		}
		//OnlyforTestStandards(list);
		List<WebModelVo> webModelVoList = new ArrayList<>();
		//先处理主表部分
		for (Class<?> cl : list) {
			if (cl.getAnnotation(WVo.class) != null) {
				//说明是主表.主表可能在子表先处理的时候，在集合中先找一下webvo
				WebModelVo wvo = new WebModelVo();
				if(cl.getAnnotation(Table.class)!=null){
					wvo.getTableVoDomain().setTableName(cl.getAnnotation(Table.class).name());
				}else {
					wvo.getTableVoDomain().setTableName(cl.getSimpleName());
				}

				webModelVoList.add(wvo);
				/*
				Optional<WebModelVo> opwvo=webModelVoList.stream()
								.filter(x->x.getTableVoDomain().getTableName()==cl.getAnnotation(Table.class).name())
										.findFirst();
				if(opwvo.isPresent()){
					//wvo=opwvo.get();
					break;
				}else {
					wvo=new WebModelVo();
					wvo.getTableVoDomain().setTableName(cl.getAnnotation(Table.class).name());
					webModelVoList.add(wvo);
				}*/
				HandleWebVo handleWebVo=new HandleWebVo2();
				//handleWebVo(cl, wvo);//将WVO的内容，处理在WebVO中
				handleWebVo.handleWebVo(cl, wvo);

				//处理的时候，不会碰到ManyToOne，OneToOne，JoinColumn等
				//tbfacaService.handleTableVo(cl, wvo.getTableVoDomain());
				tbfacaService.handleTableVo(cl, wvo);
				//fieldfacaService.handleFieldVo(cl, wvo.getTableVoDomain(), webModelVoList);
				fieldfacaService.handleFieldVo(cl, wvo, webModelVoList);
			}
		}
		//处理子表部分，主子表的差异，主要是是否有WVO的注解，如果有WVO的注解，那么就是主表，如果没有这个WVO的注解，只有TVO注解，那么就是子表
		for (Class<?> cl : list) {
			if (cl.getAnnotation(WVo.class) == null) {
				//是子表，但是在一开始不知道是哪一个的子表。先处理TableVoDomain。然后在ManyToOne的地方找它的父亲

				/*TableVoDomain tableVoDomain = new TableVoDomain();
				tbfacaService.handleTableVo(cl, tableVoDomain);//先把表的信息赋值给TableVoDomain。
				fieldfacaService.handleFieldVo(cl, tableVoDomain, webModelVoList);*/
				if(cl.getSimpleName().contains("DefaultTestOrderProduct")){
					int j=1;
				}
				log.info("当前正在处理的子表为{}:"+cl.getSimpleName());
				WebModelVo webModelVo=new WebModelVo();
				tbfacaService.handleTableVo(cl, webModelVo);//先把表的信息赋值给TableVoDomain。
				fieldfacaService.handleFieldVo(cl, webModelVo, webModelVoList);
			}
		}
		//统一处理一下WVO中的fieldRowNum，在前面设置的是formTemplate.前面设置不管他，在这个地方进行重新设置，这个是容错性处理
		for(WebModelVo wvo:webModelVoList){
			//实际上是maintable是设置了2. 其他表采用默认值，子表不设置
			if(wvo.getTableVoDomain().getEnumTableType()== EnumTableType.MAINTABLE){
				wvo.getTableVoDomain().setFormTemplate(String.valueOf(EnumModelType.MANY.getCode()));
			}
		}

		for (WebModelVo wvo : webModelVoList) {
			sortWebModelVo(wvo);
			replacenullfrom(wvo);
			log.info("jpa对象：{}，字符串发送：{}", wvo.getTableVoDomain().getTableName(), new Gson().toJson(wvo));
			//3.调用远程服务
			try {
				String result = "";
				if (wvo.getModeltype() == EnumModelType.MANY) {
					//String urlOneToMany = "http://localhost:8099/jeecg-boot/online/codeGeneratesingletablewithouttree";
					String urlOneToMany =jpaserverurl;
					result = HttpUtils.sendPost(urlOneToMany, wvo);
				}
				if (wvo.getModeltype() == EnumModelType.ONE) {
					//String urlOneTable = "http://localhost:8099/jeecg-boot/online/codeGeneratesingletablewithtree";
					String urlOneTable = jpaserverurl;
					result = HttpUtils.sendPost(urlOneTable, wvo);
				}
				if (wvo.getModeltype() == EnumModelType.TREE) {
					//String urlOneTableWithTree = "http://localhost:8099/jeecg-boot/online/codeGenerateonetomanytable";
					String urlOneTableWithTree = jpaserverurl;
					result = HttpUtils.sendPost(urlOneTableWithTree, wvo);
				}
				log.info(result);
			}catch (Exception ex){
				log.error(ex.toString());
			}
		}
	}


	private void replacenullfrom(WebModelVo wvo) {
		//通过反射，将是""的，全部替换为null

	}

	private void sortWebModelVo(WebModelVo wvo) {
		wvo.getTableVoDomain().getColumnVoDomainList().sort(new Comparator<ColumnVoDomain>() {
			@Override
			public int compare(ColumnVoDomain o1, ColumnVoDomain o2) {
				return o1.getPageVo().getOrderNum()>o2.getPageVo().getOrderNum()?1:o1.getPageVo().getOrderNum()==o2.getPageVo().getOrderNum()?0:-1;
			}
		});
		for(TableVoDomain tableVoDomain:wvo.getTableVoDomain().getSonTabeleVoDomain()){
			tableVoDomain.getColumnVoDomainList().sort(new Comparator<ColumnVoDomain>() {
				@Override
				public int compare(ColumnVoDomain o1, ColumnVoDomain o2) {
					return o1.getPageVo().getOrderNum()>o2.getPageVo().getOrderNum()?1:o1.getPageVo().getOrderNum()==o2.getPageVo().getOrderNum()?0:-1;
				}
			});
		}

	}


	/**
	 *
	 * @return
	 */
	private Resource[] getUserdefine(){
		Resource[] resources=null;
		try {
			//spring工具类，可以获取指定路径下的全部类
			ResourcePatternResolver resourcePatternResolver = new PathMatchingResourcePatternResolver();

			final String User_Define_BASE_PACKAGE = "org.jeecg.userdefine";
			String pattern = ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX + ClassUtils.convertClassNameToResourcePath(User_Define_BASE_PACKAGE) + RESOURCE_PATTERN;
			 resources = resourcePatternResolver.getResources(pattern);
		}catch (Exception ex){

		}
		return  resources;
	}
	/**
	 *
	 * @param sample
	 * @param userdefine
	 * @return
	 */
	private Resource[] subbine(Resource[] userdefine,Resource[] sample){
		int samplesize=sample.length;
		int userdefinesize=userdefine.length;
		Resource[] resources=new Resource[userdefinesize-samplesize];
		try {
			int count=0;

			for(int i=0;i<userdefinesize;i++){
				for(int j=0;j<samplesize;j++){
					if(!((FileSystemResource)userdefine[i]).getFile().getAbsolutePath().equalsIgnoreCase(((FileSystemResource)sample[j]).getFile().getAbsolutePath())){
						resources[count]=userdefine[i];
						count++;
						break;
					}
				}

			}
		}catch (Exception ex){
			log.error(ex.toString());
		}

		return resources;
	}

	/*
	 * 获取指定路径的所有jpa类
	 */
	private List<Class<?>> queryAllJpa(){
		List<Class<?>>list = new ArrayList<>();
        try {
        	//spring工具类，可以获取指定路径下的全部类
            ResourcePatternResolver resourcePatternResolver = new PathMatchingResourcePatternResolver();
			String pattern = ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX + ClassUtils.convertClassNameToResourcePath(BASE_PACKAGE) + RESOURCE_PATTERN;
			Resource[] resources = resourcePatternResolver.getResources(pattern);


			//userdefineonly,sampleonly,all
        	if(includedeployway.equalsIgnoreCase("all")){
				String BASEPACKAGE = BASE_PACKAGE;
				String RESOURCEPA = "/**/*.class";
				pattern = ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX + ClassUtils.convertClassNameToResourcePath(BASEPACKAGE) + RESOURCEPA;
				Resource[] resourcesA = resourcePatternResolver.getResources(pattern);


				BASEPACKAGE = "org.jeecg.userdefine.示例代码";
				RESOURCEPA = "/**/*.class";
				pattern = ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX + ClassUtils.convertClassNameToResourcePath(BASEPACKAGE) + RESOURCEPA;
				Resource[] resourcesB=resourcePatternResolver.getResources(pattern);

				resources=subbine(resourcesA,resourcesB);



				//resources = resourcePatternResolver.getResources(pattern);
				//resources=getUserdefine();
			}else if(includedeployway.equalsIgnoreCase("sampleonly")){
				String BASEPACKAGE = "org.jeecg.userdefine.示例代码";
				String RESOURCEPA = "/**/*.class";
				pattern = ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX + ClassUtils.convertClassNameToResourcePath(BASEPACKAGE) + RESOURCEPA;
				resourcePatternResolver.getResources(pattern);
				resources = resourcePatternResolver.getResources(pattern);
			}else {//it should be all
				if(includedeployway.equalsIgnoreCase("userdefineonly")){
					String BASEPACKAGE = BASE_PACKAGE;
					String RESOURCEPA = "/**/*.class";
					pattern = ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX + ClassUtils.convertClassNameToResourcePath(BASEPACKAGE) + RESOURCEPA;
					resourcePatternResolver.getResources(pattern);
					resources = resourcePatternResolver.getResources(pattern);
					//resources=combine(resources,userdefineresource);
				}else {
					log.error("用户选择部署的方式有错误，只能在userdefineonly,sampleonly,all 3个中选择一个。");
				}
			}




            //MetadataReader 的工厂类
            MetadataReaderFactory refractory = new CachingMetadataReaderFactory(resourcePatternResolver);
            for (Resource resource : resources) {
                //用于读取类信息
                MetadataReader reader = refractory.getMetadataReader(resource);
                //扫描到的class
                String classname = reader.getClassMetadata().getClassName();
                
                Class<?> cl = Class.forName(classname);
               /* if (cl.getAnnotation(org.hibernate.annotations.Table.class) != null) {
                	list.add(cl);
                }*/
				list.add(cl);
            }
        } catch (Exception exception) {
        }
		
		return list;
	}




}
